package com.example.myapplication.base;

import android.content.Context;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;



import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Fragment管理器类
 */
public class UIFragmentManager {

    private static final String TAG = "UIFragmentManager";

    private final Map<String, UITabInfo> mTabInfoMap = new HashMap<>();
    private final List<UIFragment> mDefaultBackStack = new ArrayList<>();
    private final Object mLock = new Object();
    @NonNull
    private final Context mAppContext;
    @IdRes
    private final int mContainerViewId;
    @NonNull
    private final FragmentManager mFragmentManager;
    @NonNull
    private List<UIFragment> mBackStack;
    @Nullable
    private String mSelectedTabName;

    /**
     * 默认弹出动画
     */
    @Nullable
    private UITransitionAnimation mDefaultPushAnimation =
            UITransitionAnimation.TRANSIT_FRAGMENT_OPEN;

    /**
     * 默认退出动画
     */
    @Nullable
    private UITransitionAnimation mDefaultPopAnimation =
            UITransitionAnimation.TRANSIT_FRAGMENT_CLOSE;

    /**
     * 默认标签切换动画
     */
    @Nullable
    private UITransitionAnimation mDefaultSelectTabAnimation =
            UITransitionAnimation.TRANSIT_FRAGMENT_FADE;

    UIFragmentManager(@NonNull Context context, @IdRes int containerViewId,
                      @NonNull FragmentManager fragmentManager) {
        mAppContext = context.getApplicationContext();
        mContainerViewId = containerViewId;
        mFragmentManager = fragmentManager;
        mBackStack = mDefaultBackStack;
    }

    /**
     * 获取默认弹出动画。
     *
     * @return 默认弹出动画 {@link UITransitionAnimation #TRANSIT_FRAGMENT_OPEN}
     */
    @Nullable
    public UITransitionAnimation getDefaultPushAnimation() {
        return mDefaultPushAnimation;
    }

    /**
     * 设置默认弹出动画。
     *
     * @param animation 默认弹出动画，或者传入{@code null}不设默认动画。
     */
    public void setDefaultPushAnimation(@Nullable UITransitionAnimation animation) {
        mDefaultPushAnimation = animation;
    }

    /**
     * 获取默认返回动画。
     *
     * @return 默认返回动画 {@link UITransitionAnimation #TRANSIT_FRAGMENT_CLOSE}。
     */
    @Nullable
    public UITransitionAnimation getDefaultPopAnimation() {
        return mDefaultPopAnimation;
    }

    /**
     * 设置默认返回动画。
     *
     * @param animation 默认返回动画，或者传入{@code null}不设默认动画。
     */
    public void setDefaultPopAnimation(@Nullable UITransitionAnimation animation) {
        mDefaultPopAnimation = animation;
    }

    /**
     * 获取标签默认切换动画。
     *
     * @return 默认标签切换动画 {@link UITransitionAnimation #TRANSIT_FRAGMENT_FADE}
     */
    @Nullable
    public UITransitionAnimation getDefaultSelectTabAnimation() {
        return mDefaultSelectTabAnimation;
    }

    /**
     * 设置默认标签切换动画
     *
     * @param animation 默认标签切换动画，或者传入{@code null}不设默认动画。
     */
    public void setDefaultSelectTabAnimation(@Nullable UITransitionAnimation animation) {
        mDefaultSelectTabAnimation = animation;
    }

    /**
     * 获取返回栈。
     *
     * @return 返回栈。
     */
    @SuppressWarnings("unchecked")
    @NonNull
    public List<UIFragment> getBackStack() {
        synchronized (mLock) {
            return (List<UIFragment>) ((ArrayList<UIFragment>) mBackStack).clone();
        }
    }

    /**
     * 获取返回栈大小。
     *
     * @return 返回栈大小。
     */
    public int getBackStackCount() {
        synchronized (mLock) {
            return mBackStack.size();
        }
    }

    /**
     * 获取返回栈内容。
     *
     * @param index 内容索引。
     * @return 返回栈内容。
     */
    @NonNull
    public UIFragment getBackStackAt(int index) {
        synchronized (mLock) {
            try {
                //TODO：需要完善下，越界抛出异常属于系统api行为，自己封装就不要这么做了
                return mBackStack.get(index);
            } catch (IndexOutOfBoundsException e) {
                throw new IllegalArgumentException("Parameter index is invalid", e);
            }
        }
    }

    /**
     * 判断Fragment是否在返回栈中。
     *
     * @param fragment Fragment对象。
     * @return {@code true}表示Fragment在返回栈中，{@code false}表示Fragment不在返回栈中。
     */
    public boolean isInBackStack(@Nullable UIFragment fragment) {
        synchronized (mLock) {
            return mBackStack.contains(fragment);
        }
    }

    /**
     * 判断Fragment标签是否在返回栈中。
     *
     * @param tag Fragment标签。
     * @return {@code true}表示Fragment标签在返回栈中，{@code false}表示Fragment标签不在返回栈中。
     */
    public boolean isInBackStack(@Nullable String tag) {
        synchronized (mLock) {
            if (tag != null) {
                for (UIFragment fragment : mBackStack) {
                    if (tag.equals(fragment.getTag())) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

    /**
     * 设置返回栈。
     *
     * @param backStack   返回栈，不可以是空的，不可以包含{@code null}，不可以包含重复的元素，不可以包含新创建
     *                    的对象。
     * @param transaction Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return {@code true}表示设置成功，{@code false}表示设置失败。
     */
    public boolean setBackStack(@NonNull List<? extends UIFragment> backStack,
                                @Nullable UIFragmentTransaction transaction) {
        ArgUtils.checkNotEmpty("backStack", backStack);
        ArgUtils.checkNotContainsNull("backStack", backStack);
        ArgUtils.checkNotContainsDuplicates("backStack", backStack);
        synchronized (mLock) {
            for (UIFragment fragment : backStack) {
                if (!mBackStack.contains(fragment)) {
                    throw new IllegalArgumentException("Parameter backStack must not contain new fragments");
                }
            }
            if (isIllegalState()) {
                return false;
            }
            final FragmentTransaction fragmentTransaction = beginTransaction();
            if (transaction != null) {
                transaction.fillFragmentTransaction(fragmentTransaction);
            }
            boolean needsCommit = false;
            for (UIFragment fragment : mBackStack) {
                if (!backStack.contains(fragment)) {
                    fragmentTransaction.remove(fragment);
                    needsCommit = true;
                }
            }
            final UIFragment oldFragment = mBackStack.get(mBackStack.size() - 1);
            mBackStack.clear();
            mBackStack.addAll(backStack);
            final UIFragment newFragment = backStack.get(backStack.size() - 1);
            if (!newFragment.equals(oldFragment)) {
                if (backStack.contains(oldFragment)) {
                    fragmentTransaction.detach(oldFragment);
                }
                fragmentTransaction.attach(newFragment);
                needsCommit = true;
            }
            if (needsCommit) {
                fragmentTransaction.commitNow();
            }
            return true;
        }
    }

    /**
     * 设置根Fragment。
     * <p>
     * 如果返回栈不是空的，那么调用此方法将不会产生影响。
     *
     * @param fragmentInfo Fragment信息。
     * @return 根Fragment，如果返回栈不是空的，或者设置失败则返回{@code null}。
     */
    @Nullable
    public UIFragment setRoot(@NonNull UIFragmentInfo fragmentInfo) {
        ArgUtils.checkNonNull("fragmentInfo", fragmentInfo);
        final UIFragment fragment = instantiate(fragmentInfo);
        return setRoot(fragment, fragmentInfo.getTag()) ? fragment : null;
    }

    /**
     * 设置根Fragment。
     * <p>
     * 如果返回栈不是空的，那么调用此方法将不会产生影响。
     *
     * @param fragment Fragment对象。
     * @param tag      Fragment标签，或者传入{@code null}不设标签。
     * @return {@code true}表示设置成功，{@code false}表示设置失败。
     */
    public boolean setRoot(@NonNull UIFragment fragment, @Nullable String tag) {
        ArgUtils.checkNonNull("fragment", fragment);
        synchronized (mLock) {
            if (!mBackStack.isEmpty() || isIllegalState()) {
                return false;
            }
            final FragmentTransaction fragmentTransaction = beginTransaction();
            fragment.mFragmentManager = this;
            mBackStack.add(fragment);
            fragmentTransaction.add(mContainerViewId, fragment, tag);
            fragmentTransaction.commitNow();
            return true;
        }
    }

    /**
     * 弹出一个新的Fragment。
     *
     * @param fragmentInfo Fragment信息。
     * @param transaction  Fragment弹出跳转参数，或者传入{@code null}使用默认参数。
     * @return 已弹出的Fragment，如果弹出失败则返回{@code null}。
     */
    @Nullable
    public UIFragment push(@NonNull UIFragmentInfo fragmentInfo,
                           @Nullable UIPushTransaction transaction) {
        ArgUtils.checkNonNull("fragmentInfo", fragmentInfo);
        final UIFragment newFragment = instantiate(fragmentInfo);
        return push(newFragment, fragmentInfo.getTag(), transaction) ? newFragment : null;
    }

    /**
     * 弹出一个新的Fragment。
     *
     * @param newFragment 新的Fragment对象。
     * @param tag         Fragment标签，或者传入{@code null}不设标签。
     * @param transaction Fragment弹出跳转参数，或者传入{@code null}使用默认参数。
     * @return {@code true}表示弹出成功，{@code false}表示弹出失败。
     */
    public boolean push(@NonNull UIFragment newFragment, @Nullable String tag,
                        @Nullable UIPushTransaction transaction) {
        ArgUtils.checkNonNull("newFragment", newFragment);
        if (isInBackStack(newFragment)) {
            return false;
        }
        synchronized (mLock) {
            if (mBackStack.isEmpty() || isIllegalState()) {
                return false;
            }
            final FragmentTransaction fragmentTransaction = beginTransaction();
            if (transaction == null) {
                transaction = new UIPushTransaction(mDefaultPushAnimation);
            }
            transaction.fillFragmentTransaction(fragmentTransaction);
            final UIFragment oldFragment = mBackStack.get(mBackStack.size() - 1);
            if (oldFragment.getPushTag() == null) {
                // 如果tag为空，则正常detach，否则无操作（为了优化画页切换耗时，防止首页等内存泄漏）
                fragmentTransaction.detach(oldFragment);
            }
            newFragment.mFragmentManager = this;
            newFragment.mPopAnimation = transaction.getPopAnimation();
            mBackStack.add(newFragment);
            fragmentTransaction.add(mContainerViewId, newFragment, tag);
            fragmentTransaction.commitNow();
            return true;
        }
    }

    /**
     * 弹出一个新的Fragment，并在其返回后回调结果。
     *
     * @param fragmentInfo Fragment信息。
     * @param transaction  Fragment弹出跳转参数，或者传入{@code null}使用默认参数。
     * @param target       结果回调目标Fragment。
     * @param requestCode  请求码，如果大于或等于0的话，会在Fragment返回后，回调给目标Fragment的
     *                     {@link UIFragment#onFragmentResult}方法。
     * @return 已弹出的Fragment，如果弹出失败则返回{@code null}。
     */
    @Nullable
    public UIFragment pushForResult(@NonNull UIFragmentInfo fragmentInfo,
                                    @Nullable UIPushTransaction transaction,
                                    @NonNull UIFragment target, int requestCode) {
        ArgUtils.checkNonNull("fragmentInfo", fragmentInfo);
        ArgUtils.checkNonNull("target", target);
        final UIFragment newFragment = instantiate(fragmentInfo);
        return pushForResult(newFragment, fragmentInfo.getTag(),
                transaction, target, requestCode) ? newFragment : null;
    }

    /**
     * 弹出一个新的Fragment，并在其返回后回调结果。
     *
     * @param newFragment 新的Fragment对象。
     * @param tag         Fragment标签，或者传入{@code null}不设标签。
     * @param transaction Fragment弹出跳转参数，或者传入{@code null}使用默认参数。
     * @param target      结果回调目标Fragment。
     * @param requestCode 请求码，如果大于或等于0的话，会在Fragment返回后，回调给目标Fragment的
     *                    {@link UIFragment#onFragmentResult}方法。
     * @return {@code true}表示弹出成功，{@code false}表示弹出失败。
     */
    public boolean pushForResult(@NonNull UIFragment newFragment, @Nullable String tag,
                                 @Nullable UIPushTransaction transaction,
                                 @NonNull UIFragment target, int requestCode) {
        ArgUtils.checkNonNull("newFragment", newFragment);
        ArgUtils.checkNonNull("target", target);
        if (push(newFragment, tag, transaction)) {
            if (requestCode >= 0) {
                try {
                    newFragment.setTargetFragment(target, requestCode);
                } catch (Exception e) {
                    Log.e(TAG, "setTargetFragment newFragment " + newFragment + "target " + target + "requestCode " + requestCode + "Exception " + e.getMessage());
                }
            }
            return true;
        }
        return false;
    }

    /**
     * 退出当前Fragment。
     *
     * @param transaction Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return 已退出的Fragment，如果退出失败则返回{@code null}。
     */
    @Nullable
    public UIFragment pop(@Nullable UIFragmentTransaction transaction) {
        final List<UIFragment> list = pop(1, transaction);
        return list.isEmpty() ? null : list.get(0);
    }

    /**
     * 返回到根Fragment。
     *
     * @param transaction Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return 已退出的Fragment列表，如果退出失败则返回空的列表。
     */
    @NonNull
    public List<UIFragment> popToRoot(@Nullable UIFragmentTransaction transaction) {
        synchronized (mLock) {
            return pop(mBackStack.size() - 1, transaction);
        }
    }

    /**
     * 返回到Fragment。
     *
     * @param tag         目标Fragment的标签。
     * @param transaction Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return 已退出的Fragment列表，如果退出失败则返回空的列表。
     */
    @NonNull
    public List<UIFragment> popTo(@NonNull String tag,
                                  @Nullable UIFragmentTransaction transaction) {
        ArgUtils.checkNonNull("tag", tag);
        synchronized (mLock) {
            final int subSize = mBackStack.size() - 2;
            int count = 1;
            for (int i = subSize; i >= 0; i--) {
                if (tag.equals(mBackStack.get(i).getTag())) {
                    break;
                }
                count++;
            }
            return pop(count, transaction);
        }
    }

    /**
     * 返回到Fragment。
     *
     * @param fragment    目标Fragment。
     * @param transaction Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return 已退出的Fragment列表，如果退出失败则返回空的列表。
     */
    @NonNull
    public List<UIFragment> popTo(@NonNull UIFragment fragment,
                                  @Nullable UIFragmentTransaction transaction) {
        ArgUtils.checkNonNull("fragment", fragment);
        synchronized (mLock) {
            final int subSize = mBackStack.size() - 2;
            int count = 1;
            for (int i = subSize; i >= 0; i--) {
                if (fragment.equals(mBackStack.get(i))) {
                    break;
                }
                count++;
            }
            return pop(count, transaction);
        }
    }

    /**
     * 替换栈顶Fragment。
     * <p>
     * 如果返回栈是空的，那么调用此方法将不会产生影响。
     *
     * @param fragmentInfo Fragment信息。
     * @param transaction  Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return 已替换的Fragment，如果返回栈是空的，或者替换失败则返回{@code null}。
     */
    @Nullable
    public UIFragment replaceTop(@NonNull UIFragmentInfo fragmentInfo,
                                 @Nullable UIFragmentTransaction transaction) {
        ArgUtils.checkNonNull("fragmentInfo", fragmentInfo);
        final UIFragment newFragment = instantiate(fragmentInfo);
        return replaceTop(newFragment, fragmentInfo.getTag(), transaction) ? newFragment : null;
    }

    /**
     * 替换栈顶Fragment。
     * <p>
     * 如果返回栈是空的，那么调用此方法将不会产生影响。
     *
     * @param newFragment 新的Fragment对象。
     * @param tag         Fragment标签，或者传入{@code null}不设标签。
     * @param transaction Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return {@code true}表示替换成功，{@code false}表示替换失败。
     */
    public boolean replaceTop(@NonNull UIFragment newFragment, @Nullable String tag,
                              @Nullable UIFragmentTransaction transaction) {
        ArgUtils.checkNonNull("newFragment", newFragment);
        if (isInBackStack(newFragment)) {
            return false;
        }
        synchronized (mLock) {
            if (mBackStack.isEmpty() || isIllegalState()) {
                return false;
            }
            final FragmentTransaction fragmentTransaction = beginTransaction();
            if (transaction != null) {
                transaction.fillFragmentTransaction(fragmentTransaction);
            }
            final int count = mBackStack.size();
            final UIFragment oldFragment = mBackStack.get(count - 1);
            fragmentTransaction.remove(oldFragment);
            newFragment.mFragmentManager = this;
            mBackStack.set(count - 1, newFragment);
            fragmentTransaction.add(mContainerViewId, newFragment, tag);
            fragmentTransaction.commitNow();
            return true;
        }
    }

    /**
     * 清空返回栈。
     *
     * @return {@code true}表示清空成功，{@code false}表示清空失败。
     */
    public boolean clear() {
        synchronized (mLock) {
            if (isIllegalState()) {
                return false;
            }
            if (!mBackStack.isEmpty()) {
                final FragmentTransaction fragmentTransaction = beginTransaction();
                for (UIFragment fragment : mBackStack) {
                    fragmentTransaction.remove(fragment);
                }
                fragmentTransaction.commitNow();
            }
            mBackStack.clear();
            return true;
        }
    }

    /**
     * 清空当前栈中除栈顶和栈底外其他的fragment
     *
     * @return {@code true}表示清空成功，{@code false}表示清空失败。
     */
    public boolean clearContent() {
        synchronized (mLock) {
            if (isIllegalState()) {
                return false;
            }
            // 栈中超过3个fragment才会执行下面的操作
            if (!mBackStack.isEmpty() && mBackStack.size() > 2) {
                final FragmentTransaction fragmentTransaction = beginTransaction();
                // 栈顶和栈底两个fragment不参与循环操作
                for (int i = mBackStack.size() - 2; i > 0; i--) {
                    UIFragment fragment = mBackStack.get(i);
                    fragmentTransaction.remove(fragment);
                    mBackStack.remove(fragment);
                }
                fragmentTransaction.commitNow();
            }
            return true;
        }
    }

    /**
     * 获取栈顶Fragment对象。
     *
     * @return 栈顶Fragment对象，如果返回栈是空的则返回{@code null}。
     */
    @Nullable
    public UIFragment peekTop() {
        synchronized (mLock) {
            final int size = mBackStack.size();
            return size < 1 ? null : mBackStack.get(size - 1);
        }
    }

    /**
     * 添加一个新的Tab栈信息，如果本地TabMap中没有信息，则默认选中本次添加的TabInfo
     *
     * @param tabInfo TabInfo栈信息
     * @return {@code true}表示添加成功，{@code false}表示添加失败。
     */
    public boolean addTab(@NonNull UITabInfo tabInfo) {
        ArgUtils.checkNonNull("tabInfo", tabInfo);
        synchronized (mTabInfoMap) {
            if (mTabInfoMap.get(tabInfo.getName()) != null || isIllegalState()) {
                return false;
            }
            mTabInfoMap.put(tabInfo.getName(), tabInfo);
            if (mSelectedTabName == null) {
                setSelectedTabName(tabInfo.getName(), null);
            }
            return true;
        }
    }

    /**
     * 移除指定Tag关键字的Tab栈信息
     *
     * @param name 标签名字，即Tag关键字
     * @return {@code true}表示添加成功，{@code false}表示添加失败。
     */
    public boolean removeTab(@NonNull String name) {
        ArgUtils.checkNonNull("name", name);
        synchronized (mTabInfoMap) {
            final UITabInfo tabInfo = mTabInfoMap.get(name);
            if (tabInfo == null || name.equals(mSelectedTabName) || isIllegalState()) {
                return false;
            }
            remove(tabInfo.mBackStack);
            mTabInfoMap.remove(name);
            return true;
        }
    }

    /**
     * 获取当前选中的Tab名字 {@link UITabInfo}
     *
     * @return 返回选中TabInfo，name信息
     */
    @Nullable
    public String getSelectedTabName() {
        return mSelectedTabName;
    }

    /**
     * 设置选中的Tab栈信息，根据参数name匹配UITabInfo，根据UITabInfo.getFragmentInfo
     * 获取FragmentInfo，用于显示在最新的栈顶中
     *
     * @param name        匹配Tab关键字
     * @param transaction Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return UIFragment，最新栈顶对象
     */
    @Nullable
    public UIFragment setSelectedTabName(@NonNull String name,
                                         @Nullable UIFragmentTransaction transaction) {
        ArgUtils.checkNonNull("name", name);
        final UITabInfo tabInfo = mTabInfoMap.get(name);
        if (tabInfo == null || isIllegalState()) {
            return null;
        }
        synchronized (mLock) {
            if (!mDefaultBackStack.isEmpty()) {
                remove(mDefaultBackStack);
                mDefaultBackStack.clear();
            }
            final FragmentTransaction fragmentTransaction = beginTransaction();
            final UIFragment oldFragment = peekTop();
            if (oldFragment != null) {
                if (transaction == null) {
                    transaction = new UIFragmentTransaction(mDefaultSelectTabAnimation);
                }
                transaction.fillFragmentTransaction(fragmentTransaction);
            }
            mBackStack = tabInfo.mBackStack;
            final UIFragment newFragment;
            boolean needsCommit = false;
            if (mBackStack.isEmpty()) {
                if (oldFragment != null) {
                    fragmentTransaction.hide(oldFragment);
                }
                newFragment = instantiate(tabInfo.getFragmentInfo());
                newFragment.mFragmentManager = this;
                mBackStack.add(newFragment);
                fragmentTransaction.add(mContainerViewId, newFragment,
                        tabInfo.getFragmentInfo().getTag());
                needsCommit = true;
            } else {
                newFragment = mBackStack.get(mBackStack.size() - 1);
                if (!newFragment.equals(oldFragment)) {
                    if (oldFragment != null) {
                        fragmentTransaction.hide(oldFragment);
                    }
                    fragmentTransaction.show(newFragment);
                    needsCommit = true;
                }
            }
            if (needsCommit) {
                fragmentTransaction.commitNow();
            }
            mSelectedTabName = tabInfo.getName();
            return newFragment;
        }
    }

    /**
     * 退出固定数量的画页，直接操作画页堆栈
     *
     * @param count       后退画页的数量，count<0 或者 count>堆栈size，直接返回空的list
     * @param transaction Fragment跳转参数，或者传入{@code null}使用默认参数。
     * @return 退出画页的list，按照top，top-1的顺序存储。即原堆栈中Top画页在返回list.get(0)位置
     */
    @NonNull
    private List<UIFragment> pop(int count, @Nullable UIFragmentTransaction transaction) {
        final List<UIFragment> list = new ArrayList<>();
        if (isIllegalState()) {
            return list;
        }
        synchronized (mLock) {
            final int size = mBackStack.size();
            if (count > 0 && count < size) {
                final FragmentTransaction fragmentTransaction = beginTransaction();
                final UIFragment oldFragment = mBackStack.get(size - 1);
                if (transaction == null) {
                    transaction = new UIFragmentTransaction(oldFragment.mPopAnimation == null
                            ? mDefaultPopAnimation : oldFragment.mPopAnimation);
                }
                transaction.fillFragmentTransaction(fragmentTransaction);
                for (int i = 1; i <= count; i++) {
                    final UIFragment fragment = mBackStack.remove(size - i);
                    fragmentTransaction.remove(fragment);
                    list.add(fragment);
                }
                final UIFragment newFragment = mBackStack.get(size - count - 1);
                if (newFragment.isDetached()) {
                    // 判断是否被detach过，如果是则说明非特殊页面（部分页面不想被detach，优化页面切换耗时，防止内存泄漏）
                    fragmentTransaction.attach(newFragment);
                }
                fragmentTransaction.commitNow();
                for (UIFragment fragment : list) {
                    if (newFragment.equals(fragment.getTargetFragment())) {
                        fragment.notifyFragmentResult();
                        break;
                    }
                }
            }
        }
        return list;
    }

    /**
     * 批量移除fragment信息，此方法只处理系统API对Fragment的操作，不对Base中封装的画页栈列表做处理。
     * 具体参考{@link FragmentTransaction}
     *
     * @param fragments 要移除的fragment list
     */
    private void remove(@NonNull Collection<? extends UIFragment> fragments) {
        if (fragments.isEmpty()) {
            return;
        }
        final FragmentTransaction fragmentTransaction = beginTransaction();
        for (UIFragment fragment : fragments) {
            fragmentTransaction.remove(fragment);
        }
        fragmentTransaction.commitNow();
    }

    /**
     * 根据 UIFragmentInfo 实例化 UIFragment对象
     *
     * @param fragmentInfo 实例化fragment信息
     * @return 实例化后的UIFragment对象
     */
    @NonNull
    private UIFragment instantiate(@NonNull UIFragmentInfo fragmentInfo) {
        final UIFragment fragment = (UIFragment) mFragmentManager.getFragmentFactory()
                .instantiate(mAppContext.getClassLoader(), fragmentInfo.getClassName());
        final Bundle args = fragmentInfo.getArguments();
        if (args != null) {
            args.setClassLoader(fragment.getClass().getClassLoader());
            fragment.setArguments(args);
        }
        return fragment;
    }

    @NonNull
    private FragmentTransaction beginTransaction() {
        return mFragmentManager.beginTransaction().disallowAddToBackStack();
    }

    /**
     * 判断当前是否在非法状态。
     * isStateSaved，表示已经走入 onSaveInstanceState 方法，处于不能操作状态
     * isDestroyed, 表示已经销毁，处于不能操作状态
     *
     * @return {@code true}当前是非法状态，{@code false}当前不是非法状态。
     */
    private boolean isIllegalState() {
        if (mFragmentManager.isStateSaved()) {
            Log.w(TAG, new IllegalStateException("Can not perform this action after onSaveInstanceState"));
            return true;
        }
        if (mFragmentManager.isDestroyed()) {
            Log.w(TAG, new IllegalStateException("Can not perform this action after activity onDestroy"));
            return true;
        }
        return false;
    }

    /**
     * 恢复所有经过onSaveInstanceState保存的序列化数据
     *
     * @param state 保存的序列化对象数据{@link SavedState}
     */
    public void restoreAllState(@Nullable Parcelable state) {
        if (!(state instanceof SavedState)) {
            return;
        }
        final SavedState.TabState[] tabStates = ((SavedState) state).mTabStates;
        if (tabStates != null) {
            synchronized (mTabInfoMap) {
                for (SavedState.TabState tabState : tabStates) {
                    final UITabInfo tabInfo = tabState.readTabInfo(this);
                    if (tabInfo != null) {
                        mTabInfoMap.put(tabInfo.getName(), tabInfo);
                    }
                }
            }
        }
        synchronized (mLock) {
            mSelectedTabName = ((SavedState) state).mSelectedTabName;
            final SavedState.BackStackState defaultBackStackState =
                    ((SavedState) state).mDefaultBackStackState;
            if (defaultBackStackState != null) {
                defaultBackStackState.readBackStack(this, mDefaultBackStack);
            }
            final UITabInfo selectedTabInfo = mSelectedTabName == null ? null
                    : mTabInfoMap.get(mSelectedTabName);
            mBackStack = selectedTabInfo == null ? mDefaultBackStack : selectedTabInfo.mBackStack;
        }
        mDefaultPushAnimation = ((SavedState) state).mDefaultPushAnimation;
        mDefaultPopAnimation = ((SavedState) state).mDefaultPopAnimation;
    }


    @NonNull
    Parcelable saveAllState() {
        return new SavedState(this);
    }

    static final class SavedState implements Parcelable {

        @Nullable
        private final TabState[] mTabStates;
        @Nullable
        private final BackStackState mDefaultBackStackState;
        @Nullable
        private final String mSelectedTabName;
        @Nullable
        private final UITransitionAnimation mDefaultPushAnimation;
        @Nullable
        private final UITransitionAnimation mDefaultPopAnimation;

        private SavedState(@NonNull UIFragmentManager fragmentManager) {
            final UITabInfo[] tabInfos =
                    fragmentManager.mTabInfoMap.values().toArray(new UITabInfo[0]);
            final int size = tabInfos.length;
            mTabStates = new TabState[size];
            for (int i = 0; i < size; i++) {
                mTabStates[i] = new TabState(fragmentManager.mFragmentManager, tabInfos[i]);
            }
            mDefaultBackStackState = new BackStackState(fragmentManager.mFragmentManager,
                    fragmentManager.mDefaultBackStack);
            mSelectedTabName = fragmentManager.mSelectedTabName;
            mDefaultPushAnimation = fragmentManager.mDefaultPushAnimation;
            mDefaultPopAnimation = fragmentManager.mDefaultPopAnimation;
        }

        private SavedState(@NonNull Parcel source, @Nullable ClassLoader loader) {
            mTabStates = source.createTypedArray(TabState.CREATOR);
            mDefaultBackStackState = source.readParcelable(loader);
            mSelectedTabName = source.readString();
            mDefaultPushAnimation = source.readParcelable(loader);
            mDefaultPopAnimation = source.readParcelable(loader);
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeParcelableArray(mTabStates, flags);
            dest.writeParcelable(mDefaultBackStackState, flags);
            dest.writeString(mSelectedTabName);
            dest.writeParcelable(mDefaultPushAnimation, flags);
            dest.writeParcelable(mDefaultPopAnimation, flags);
        }

        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
            @Override
            public SavedState createFromParcel(Parcel source) {
                return new SavedState(source, null);
            }

            @Override
            public SavedState createFromParcel(Parcel source, ClassLoader loader) {
                return new SavedState(source, loader);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };

        private static final class TabState implements Parcelable {

            @Nullable
            private final String mName;
            @Nullable
            private final String mFragmentClassName;
            @Nullable
            private final Bundle mFragmentArgs;
            @Nullable
            private final String mFragmentTag;
            @Nullable
            private final BackStackState mBackStackState;

            private TabState(@NonNull FragmentManager fragmentManager, @NonNull UITabInfo tabInfo) {
                mName = tabInfo.getName();
                mFragmentClassName = tabInfo.getFragmentInfo().getClassName();
                mFragmentArgs = tabInfo.getFragmentInfo().getArguments();
                mFragmentTag = tabInfo.getFragmentInfo().getTag();
                mBackStackState = new BackStackState(fragmentManager, tabInfo.mBackStack);
            }

            private TabState(@NonNull Parcel source, @Nullable ClassLoader loader) {
                mName = source.readString();
                mFragmentClassName = source.readString();
                mFragmentArgs = source.readBundle(loader);
                mFragmentTag = source.readString();
                mBackStackState = source.readParcelable(loader);
            }

            @Nullable
            private UITabInfo readTabInfo(@NonNull UIFragmentManager fragmentManager) {
                if (mName == null || mFragmentClassName == null) {
                    return null;
                }
                final UIFragmentInfo fragmentInfo =
                        new UIFragmentInfo(mFragmentClassName, mFragmentArgs, mFragmentTag);
                final UITabInfo tabInfo = new UITabInfo(mName, fragmentInfo);
                if (mBackStackState != null) {
                    mBackStackState.readBackStack(fragmentManager, tabInfo.mBackStack);
                }
                return tabInfo;
            }

            @Override
            public void writeToParcel(Parcel dest, int flags) {
                dest.writeString(mName);
                dest.writeString(mFragmentClassName);
                dest.writeBundle(mFragmentArgs);
                dest.writeString(mFragmentTag);
                dest.writeParcelable(mBackStackState, flags);
            }

            @Override
            public int describeContents() {
                return 0;
            }

            public static final Creator<TabState> CREATOR = new ClassLoaderCreator<TabState>() {
                @Override
                public TabState createFromParcel(Parcel source) {
                    return new TabState(source, null);
                }

                @Override
                public TabState createFromParcel(Parcel source, ClassLoader loader) {
                    return new TabState(source, loader);
                }

                @Override
                public TabState[] newArray(int size) {
                    return new TabState[size];
                }
            };

        }

        private static final class BackStackState implements Parcelable {

            @Nullable
            private final FragmentState[] mFragmentStates;

            private BackStackState(@NonNull FragmentManager fragmentManager,
                                   @NonNull List<? extends UIFragment> backStack) {
                final int size = backStack.size();
                mFragmentStates = new FragmentState[size];
                for (int i = 0; i < size; i++) {
                    mFragmentStates[i] = new FragmentState(fragmentManager, backStack.get(i));
                }
            }

            private BackStackState(@NonNull Parcel source) {
                mFragmentStates = source.createTypedArray(FragmentState.CREATOR);
            }

            private void readBackStack(@NonNull UIFragmentManager fragmentManager,
                                       @NonNull Collection<? super UIFragment> backStack) {
                if (mFragmentStates == null) {
                    return;
                }
                backStack.clear();
                for (FragmentState state : mFragmentStates) {
                    final UIFragment fragment = state.readFragment(fragmentManager);
                    if (fragment != null) {
                        backStack.add(fragment);
                    }
                }
            }

            @Override
            public int describeContents() {
                return 0;
            }

            @Override
            public void writeToParcel(Parcel dest, int flags) {
                dest.writeParcelableArray(mFragmentStates, flags);
            }

            public static final Creator<BackStackState> CREATOR = new Creator<BackStackState>() {
                @Override
                public BackStackState createFromParcel(Parcel source) {
                    return new BackStackState(source);
                }

                @Override
                public BackStackState[] newArray(int size) {
                    return new BackStackState[size];
                }
            };

        }

        private static final class FragmentState implements Parcelable {

            private static final String FRAGMENT = "fragment";
            private static final String FRAGMENT_STATE = "fragment_state";

            @Nullable
            private final Bundle mBundle;

            private FragmentState(@NonNull FragmentManager fragmentManager,
                                  @NonNull UIFragment fragment) {
                mBundle = new Bundle();
                fragmentManager.putFragment(mBundle, FRAGMENT, fragment);
                mBundle.putParcelable(FRAGMENT_STATE, fragment.saveAllState());
            }

            private FragmentState(@NonNull Parcel source, @Nullable ClassLoader loader) {
                mBundle = source.readBundle(loader);
            }

            @Nullable
            private UIFragment readFragment(@NonNull UIFragmentManager fragmentManager) {
                if (mBundle == null) {
                    return null;
                }
                final UIFragment fragment = (UIFragment) fragmentManager.mFragmentManager
                        .getFragment(mBundle, FRAGMENT);
                if (fragment == null) {
                    return null;
                }
                fragment.mFragmentManager = fragmentManager;
                fragment.restoreAllState(mBundle.getParcelable(FRAGMENT_STATE));
                return fragment;
            }

            @Override
            public int describeContents() {
                return 0;
            }

            @Override
            public void writeToParcel(Parcel dest, int flags) {
                dest.writeBundle(mBundle);
            }

            public static final Creator<FragmentState> CREATOR = new ClassLoaderCreator<FragmentState>() {
                @Override
                public FragmentState createFromParcel(Parcel source) {
                    return new FragmentState(source, null);
                }

                @Override
                public FragmentState createFromParcel(Parcel source, ClassLoader loader) {
                    return new FragmentState(source, loader);
                }

                @Override
                public FragmentState[] newArray(int size) {
                    return new FragmentState[size];
                }
            };
        }
    }

}
